/**
 * 
 */
package com.jplus.core.core.abstracts.defaults;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import com.jplus.core.anno.boot.Bean;
import com.jplus.core.anno.boot.Component;
import com.jplus.core.anno.boot.Configuration;
import com.jplus.core.anno.com.Autowired;
import com.jplus.core.anno.com.Lazy;
import com.jplus.core.anno.com.Order;
import com.jplus.core.anno.com.Scope;
import com.jplus.core.anno.com.Scope.EScope;
import com.jplus.core.anno.com.Value;
import com.jplus.core.core.abstracts.BeanDefinitions;
import com.jplus.core.core.beans.BeanDefinition;
import com.jplus.core.core.beans.BeanKey;
import com.jplus.core.core.events.ApplicationEvent;
import com.jplus.core.core.events.ApplicationListener;
import com.jplus.core.fault.BeansException;
import com.jplus.core.utill.Assert;
import com.jplus.core.utill.JUtil;
import com.jplus.core.utill.clazz.ClassSearchUtil;
import com.jplus.core.utill.clazz.ClassUtil;

/**
 * @author yuanqy
 */
public class DefaultBeanDefinition extends BeanDefinitions {

	private Map<String, BeanKey> beanKeys = new HashMap<>();
	private Map<BeanKey, BeanDefinition> beanDefinitions = new HashMap<>();

	private void putBeanDefinitions(BeanKey key, BeanDefinition value) {
		this.beanDefinitions.put(key, value);
		this.beanKeys.put(key.getName(), key);
	}

	private void delBeanDefinitions(BeanKey key) {
		this.beanDefinitions.remove(key);
		this.beanKeys.remove(key.getName());
	}

	/**
	 * 仅用于获取已有的BeanKey
	 */
	public BeanKey getBeanKey(String beanName, Class<?> beanClass) {
		if (beanName != null) {
			return beanKeys.get(beanName);
		} else {
			return beanDefinitions.get(new BeanKey(beanClass)).getBeanKey();
		}
	}

	private BeanDefinition createBeanDefinition(String name, Class<?> clazz) throws BeansException {
		BeanKey bk = new BeanKey(name, clazz);
		BeanDefinition bd = new BeanDefinition(bk);

		resolveBeanFields(bd);
		resolveDependences(bd);
		resolveScope(bd);
		// resolveProxy(bd);
		resolveOrder(bd);
		resolveLazy(bd);
		// resolveAware(bd);
		// resolveAction(bd);
		resolveBean(bd);
		resolveBeansLiefcycle(bd);
		resolveEvent(bd);
		resolveBeanName(bd);

		// bd.setBeanKey(bk);
		return bd;
	}

	@Override
	public Map<BeanKey, BeanDefinition> buildBeanDefinition(String packagePath) throws BeansException {
		Assert.notNull(packagePath,"[异常]未设置项目 包扫描路径：FRAME.COMPONENT_SCAN(\"frame.component-scan\")");
		List<Class<?>> listCls = ClassSearchUtil.getListByAnnotation(packagePath, Component.class);
		// 1.创建bean定义
		for (Class<?> clazz : listCls) {
			BeanDefinition bd = createBeanDefinition(null, clazz);
			putBeanDefinitions(bd.getBeanKey(), bd);
		}
		return getBeanDefinitions();
	}

	// ============================================================================

	private String getNameByAnno(String calzz) {
		String vals = calzz.substring(calzz.lastIndexOf("(") + 1, calzz.length() - 1);
		String[] vs = vals.split(",");
		for (String str : vs) {
			String[] t = str.split("=");
			if (t[0].equals("value")) {
				if (t.length == 2)
					return t[1];
				else
					return "";
			}
		}
		return "";
	}

	// ========================================================
	// ====================== 类处理 =========================
	// ========================================================

	/**
	 * 获取BeanName 处理[小复杂] 作用对象：继承了或是Component的注解的有value属性的注解的值，作为BeanName<br>
	 */
	private void resolveBeanName(BeanDefinition bd) throws BeansException {
		Annotation anobj = ClassUtil.findAnnotationParentOne(bd.getBeanClass(), Component.class);
		if (anobj != null) {
			try {
				String name = getNameByAnno(anobj.toString());
				if (!JUtil.isEmpty(name)) {
					bd.setBeanKey(new BeanKey(name, bd.getBeanClass()));
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new BeansException(e.getMessage());
			}
		}
	}

	/**
	 * Bean对象初始化,延迟实例加载
	 */
	private void resolveLazy(BeanDefinition bd) {
		Lazy lazy = bd.getBeanClass().getAnnotation(Lazy.class);
		if (lazy != null)
			bd.setLazyInit(lazy.value());
	}

	/**
	 * Bean加载排序处理 作用对象：有@Order 的类
	 */
	private void resolveOrder(BeanDefinition bd) {
		Order order = bd.getBeanClass().getAnnotation(Order.class);
		BeanKey bk = bd.getBeanKey();
		if (order != null)
			bk.setOrder(order.value());
		else
			bk.setOrder(10);
	}

	/**
	 * 字段注入处理 作用对象：有@Value 的字段
	 */
	private void resolveBeanFields(BeanDefinition bd) {
		for (Field f : bd.getBeanClass().getDeclaredFields()) {
			if ((f.getAnnotation(Value.class)) != null) {
				bd.setResourceFields(f);
			}
		}
	}

	/**
	 * 实例对象作用域处理 作用对象：有@Scope的类
	 */
	private void resolveScope(BeanDefinition bd) {
		Scope s = bd.getBeanClass().getAnnotation(Scope.class);
		bd.setScope(EScope.SINGLETON);// 默认单例
		if (s != null) {
			bd.setScope(s.value());
		}
	}

	/**
	 * 依赖关系注入处理 作用对象：有@Autowired的字段
	 */
	private void resolveDependences(BeanDefinition bd) {
		for (Field f : bd.getBeanClass().getDeclaredFields()) {
			Autowired r;
			if ((r = f.getAnnotation(Autowired.class)) != null) {
				String beanName = r.value();
				Class<?> dpClass = f.getType();
				BeanKey bk2 = new BeanKey(beanName, dpClass);
				bd.setDependences(bk2);// 设置依赖关系
				bd.setResourceFields(f);// 也算字段注入
			}
		}
	}

	/**
	 * 针对于@Configuration 下的@Bean，使用JavaConfig创建bean
	 * 
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	private void resolveBean(BeanDefinition bd) {
		try {
			if (bd.getBeanClass().isAnnotationPresent(Configuration.class)) {
				Method[] ms = bd.getBeanClass().getMethods();
				for (Method m : ms) {
					if (m.isAnnotationPresent(Bean.class)) {
						Bean bean = m.getAnnotation(Bean.class);
						String name = bean.value();
						Class<?> clazz = m.getReturnType();
						BeanDefinition bdtmp = createBeanDefinition(name, clazz);
						bdtmp.setInstanceBean(bd.getBeanKey());
						bdtmp.setInstanceMethod(m);
						if (m.isAnnotationPresent(Order.class))
							bdtmp.getBeanKey().setOrder(m.getAnnotation(Order.class).value());
						if (!JUtil.isEmpty(bean.initMethod()))
							bdtmp.setInitMethod(clazz.getMethod(bean.initMethod(), new Class<?>[] {}));
						if (!JUtil.isEmpty(bean.destroyMethod()))
							bdtmp.setDestoryMethod(clazz.getMethod(bean.destroyMethod(), new Class<?>[] {}));
						putBeanDefinitions(bdtmp.getBeanKey(), bdtmp);
					}
				}
			}
		} catch (Exception e) {
			throw new BeansException(e);
		}
	}

	/**
	 * Bean 生命周期处理 作用对象：@PostConstruct、@PreDestroy
	 */
	private void resolveBeansLiefcycle(BeanDefinition bd) {
		Method[] ms = bd.getBeanClass().getMethods();
		for (Method m : ms) {
			if (m.isAnnotationPresent(PostConstruct.class))
				bd.setPostConstruct(m);
			if (m.isAnnotationPresent(PreDestroy.class))
				bd.setPreDestory(m);
		}
	}

	/**
	 * Bean 注册事件驱动
	 */
	@SuppressWarnings("unchecked")
	private void resolveEvent(BeanDefinition bd) {
		Class<?> clazz = bd.getBeanClass();
		if (ApplicationListener.class.isAssignableFrom(clazz)) {
			for (Method m : clazz.getMethods()) {
				if (m.getName().equals("onApplicationEvent")) {
					bd.setEventClass((Class<? extends ApplicationEvent>) m.getParameterTypes()[0]);
					break;
				}
			}
		}
	}

	@Override
	public BeanDefinition buildBeanDefinition(String name, Class<?> clazz) {
		BeanDefinition bd = createBeanDefinition(name, clazz); // 类加载器加载当前类定义
		putBeanDefinitions(bd.getBeanKey(), bd);
		return bd;
	}

	@Override
	public void removeBeanDefinition(BeanKey key) {
		delBeanDefinitions(key);
	}

	@Override
	public BeanDefinition getBeanDefinition(BeanKey key) {
		return getBeanDefinitions().get(key);
	}

	public Map<BeanKey, BeanDefinition> getBeanDefinitions() {
		return beanDefinitions;
	}

	/**
	 * TODO 可以加缓存，并非每次都拷贝排序
	 */
	@Override
	public List<BeanDefinition> listSortBeanDefinitions() {
		Collection<BeanDefinition> src = getBeanDefinitions().values();
		List<BeanDefinition> list = new ArrayList<>(src.size());
		for (BeanDefinition bean : src)
			list.add(bean); // 拷贝
		Collections.sort(list);// 排序
		return list;
	}
}
